/**
 * Copyright (c) 2024-2025 National Fundamental Software of China Co., Ltd.
 *
 * You should have find a copy of NFSChina License. If not, please contact us
 * by email <os_support@nfschina>
 *
**/

/*
    SPDX-FileCopyrightText: 2011 Martin Gräßlin <mgraesslin@kde.org>
    SPDX-FileCopyrightText: 2012 Gregor Taetzner <gregor@freenet.de>
    SPDX-FileCopyrightText: 2012 Marco Martin <mart@kde.org>
    SPDX-FileCopyrightText: 2013 David Edmundson <davidedmundson@kde.org>
    SPDX-FileCopyrightText: 2015 Eike Hein <hein@kde.org>
    SPDX-FileCopyrightText: 2021 Mikel Johnson <mikel5764@gmail.com>
    SPDX-FileCopyrightText: 2021 Noah Davis <noahadvs@gmail.com>

    SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import QtQml 2.15
import QtGraphicalEffects 1.15
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 3.0 as PC3
import org.kde.plasma.private.kicker 0.1 as Kicker

import "code/tools.js" as Tools

Item {
    id: kickoff

    // The properties are defined here instead of the singleton because each
    // instance of Kickoff requires different instances of these properties

    readonly property bool inPanel: [
        PlasmaCore.Types.TopEdge,
        PlasmaCore.Types.RightEdge,
        PlasmaCore.Types.BottomEdge,
        PlasmaCore.Types.LeftEdge,
    ].includes(plasmoid.location)
    readonly property bool vertical: plasmoid.formFactor === PlasmaCore.Types.Vertical
    readonly property real scaleFactor: PlasmaCore.Units.devicePixelRatio
    // Used to prevent the width from changing frequently when the scrollbar appears or disappears
    readonly property bool mayHaveGridWithScrollBar: plasmoid.configuration.applicationsDisplay === 0
        || (plasmoid.configuration.favoritesDisplay === 0 && plasmoid.rootItem.rootModel.favoritesModel.count > minimumGridRowCount * minimumGridRowCount)


    //BEGIN Models
    readonly property Kicker.RootModel rootModel: Kicker.RootModel {
        autoPopulate: false

        appletInterface: plasmoid

        flat: true // have categories, but no subcategories
        sorted: plasmoid.configuration.alphaSort
        showSeparators: true
        showTopLevelItems: true

        showAllApps: true
        showAllAppsCategorized: false
        showRecentApps: false
        showRecentDocs: false
        showRecentContacts: false
        showPowerSession: false
        showFavoritesPlaceholder: true

        Component.onCompleted: {
            // init favorites model, call C++ function initForClient
            favoritesModel.initForClient("org.kde.plasma.kickoff.favorites.instance-" + plasmoid.id)
            if (!plasmoid.configuration.favoritesPortedToKAstats) {
                if (favoritesModel.count < 1) {
                    favoritesModel.portOldFavorites(plasmoid.configuration.favorites);
                }
                plasmoid.configuration.favoritesPortedToKAstats = true;
            }
        }
    }

    readonly property Kicker.RunnerModel runnerModel: Kicker.RunnerModel {
        query: kickoff.searchField ? kickoff.searchField.text : ""
        onRequestUpdateQuery: query => {
            if (kickoff.searchField) {
                kickoff.searchField.text = query;
            }
        }
        appletInterface: plasmoid
        mergeResults: true
        favoritesModel: rootModel.favoritesModel
    }

    readonly property Kicker.ComputerModel computerModel: Kicker.ComputerModel {
        appletInterface: plasmoid
        favoritesModel: rootModel.favoritesModel
        systemApplications: plasmoid.configuration.systemApplications
        Component.onCompleted: {
            systemApplications = plasmoid.configuration.systemApplications;
        }
    }

    readonly property Kicker.RecentUsageModel recentUsageModel: Kicker.RecentUsageModel {
        favoritesModel: rootModel.favoritesModel
    }

    readonly property Kicker.RecentUsageModel frequentUsageModel: Kicker.RecentUsageModel {
        favoritesModel: rootModel.favoritesModel
        ordering: 1 // Popular / Frequently Used
    }
    //END

    //BEGIN UI elements
    // Set in FullRepresentation.qml
    property Item header: null

    // Set in Header.qml
    property PC3.TextField searchField: null

    // Set in FullRepresentation.qml, ApplicationPage.qml, PlacesPage.qml
    property Item sideBar: null // is null when searching
    property Item contentArea: null // is searchView when searching
    //END

    property bool blurEffectValid: false

    //BEGIN Metrics
    readonly property PlasmaCore.FrameSvgItem backgroundMetrics: PlasmaCore.FrameSvgItem {
        // Inset defaults to a negative value when not set by margin hints
        readonly property real leftPadding: margins.left - Math.max(inset.left, 0)
        readonly property real rightPadding: margins.right - Math.max(inset.right, 0)
        readonly property real topPadding: margins.top - Math.max(inset.top, 0)
        readonly property real bottomPadding: margins.bottom - Math.max(inset.bottom, 0)
        readonly property real spacing: leftPadding
        visible: false
        imagePath: plasmoid.formFactor === PlasmaCore.Types.Planar ? "widgets/background" : "dialogs/background"
    }

    // This is here rather than in the singleton with the other metrics items
    // because the list delegate's height depends on a configuration setting
    // and the singleton can't access those
    readonly property real listDelegateHeight: listDelegate.height
    KickoffListDelegate {
        id: listDelegate
        visible: false
        enabled: false
        model: null
        index: -1
        text: "asdf"
        url: ""
        decoration: "start-here-kde"
        description: "asdf"
        action: null
        indicator: null
    }

    // Used to show smaller Kickoff on small screens
    readonly property int minimumGridRowCount: Math.min(Screen.desktopAvailableWidth, Screen.desktopAvailableHeight) < KickoffSingleton.gridCellSize * 4 + (Plasmoid.fullRepresentationItem ? Plasmoid.fullRepresentationItem.normalPage.preferredSideBarWidth : KickoffSingleton.gridCellSize * 2) ? 2 : 4
    //END

    Plasmoid.switchWidth: plasmoid.fullRepresentationItem ? plasmoid.fullRepresentationItem.Layout.minimumWidth : -1
    Plasmoid.switchHeight: plasmoid.fullRepresentationItem ? plasmoid.fullRepresentationItem.Layout.minimumHeight : -1

    Plasmoid.preferredRepresentation: plasmoid.compactRepresentation
    Plasmoid.backgroundHints: PlasmaCore.Types.NoBackground
    property color backgroundColor: PlasmaCore.Theme.globalIconTheme() !== "breeze-dark" ? (blurEffectValid ? "white" : "#f4f4f4") : "#1A1A1A"
    property int startMenuOpacity: 100 - PlasmaCore.Theme.startMenuOpacity()

    Plasmoid.fullRepresentation: FullRepresentation {
        focus: true
        anchors.fill:parent
        // anchors.margins: 6
        background: Rectangle {
            anchors.fill: parent
            color: backgroundColor
            radius: 12 * scaleFactor
            opacity: blurEffectValid ? startMenuOpacity / 100 : 0.95
        }
    }

    Plasmoid.icon: plasmoid.configuration.icon

    Plasmoid.compactRepresentation: MouseArea {
        id: compactRoot

        // Taken from DigitalClock to ensure uniform sizing when next to each other
        readonly property bool tooSmall: plasmoid.formFactor === PlasmaCore.Types.Horizontal && Math.round(2 * (compactRoot.height / 5)) <= PlasmaCore.Theme.smallestFont.pixelSize

        readonly property bool shouldHaveIcon: Plasmoid.formFactor === PlasmaCore.Types.Vertical || Plasmoid.icon !== ""

        readonly property var sizing: {
            const displayedIcon = buttonIcon.valid ? buttonIcon : buttonIconFallback;

            let impWidth = 0;
            if (shouldHaveIcon) {
                impWidth += displayedIcon.width;
            }
            const impHeight = Math.max(PlasmaCore.Units.iconSizeHints.panel, displayedIcon.height);

            // at least square, but can be wider/taller
            if (kickoff.inPanel) {
                if (kickoff.vertical) {
                    return {
                        minimumWidth: -1,
                        maximumWidth: -1,
                        minimumHeight: parent.width,
                        maximumHeight:  parent.width,
                    };
                } else { // horizontal
                    return {
                        minimumWidth: parent.height,
                        maximumWidth: parent.height,
                        minimumHeight: -1,
                        maximumHeight: -1,
                    };
                }
            } else {
                return {
                    minimumWidth: impWidth,
                    maximumWidth: -1,
                    minimumHeight: PlasmaCore.Units.iconSizes.small,
                    maximumHeight: -1,
                };
            }
        }

        implicitWidth: PlasmaCore.Units.iconSizeHints.panel
        implicitHeight: PlasmaCore.Units.iconSizeHints.panel

        Layout.minimumWidth: sizing.minimumWidth
        Layout.maximumWidth: sizing.maximumWidth
        Layout.minimumHeight: sizing.minimumHeight
        Layout.maximumHeight: sizing.maximumHeight

        hoverEnabled: true

        property bool wasExpanded

        onPressed: wasExpanded = Plasmoid.expanded
        onClicked: Plasmoid.expanded = !wasExpanded

        DropArea {
            id: compactDragArea
            anchors.fill: parent
        }

        Timer {
            id: expandOnDragTimer
            // this is an interaction and not an animation, so we want it as a constant
            interval: 250
            running: compactDragArea.containsDrag
            onTriggered: plasmoid.expanded = true
        }

        // Rectangle {
        //     id: bgHover
        //     anchors.fill:parent
        //     //color: Qt.rgba(255,255,255,0.1)
        //     color: "transparent"
        //     radius: 12
        //     visible:compactRoot.containsMouse
        // }
        PlasmaCore.IconItem {
            id: iconBackground

            anchors.centerIn: parent
            anchors.margins: 0
            smooth: true
            source: ""
            width: 38 * scaleFactor
            height: 38 * scaleFactor
            roundToIconSize: false
            usesPlasmaTheme: true
        }
        PlasmaCore.IconItem {
            id: buttonIcon

            anchors.centerIn: parent
            anchors.margins: 0
            width: 24 * scaleFactor
            height: 24 * scaleFactor
            roundToIconSize: false
            usesPlasmaTheme: true
            smooth: true
            source: Tools.iconOrDefault(plasmoid.formFactor, plasmoid.icon)
            active: false//compactRoot.containsMouse || compactDragArea.containsDrag
        }

        states: [
            State {
                name: "defalult"
                when: !Plasmoid.expanded && !containsMouse && !pressed
            },
            State {
                name: "default-hovered"
                when: !Plasmoid.expanded && containsMouse && !pressed
            },
            State {
                name: "default-clicked"
                when: !Plasmoid.expanded && containsMouse && pressed
            },
            State {
                name: "task-actived-one"
                when: Plasmoid.expanded && !containsMouse && !pressed
            },

            State {
                name: "task-actived-one-hover"
                when: Plasmoid.expanded && containsMouse && !pressed
           },
            State {
                name: "task-actived-one-click"
                when: Plasmoid.expanded && containsMouse && pressed
            }
        ]
        onStateChanged: {
            if (state == "default-hovered") {
                iconBackground.source = "task-pinned-hover"
            } else if (state == "default-clicked") {
                iconBackground.source = "task-pinned-click"
            } else if (state == "task-actived-one") {
                iconBackground.source = "task-actived-one"
            } else if (state == "task-actived-one-hover") {
                iconBackground.source = "task-actived-one-hover"
            } else if (state == "task-actived-one-click") {
                iconBackground.source = "task-actived-one-click"
            } else {
                iconBackground.source = ""
            }
        }
    }

    Kicker.ProcessRunner {
        id: processRunner;
    }

    function action_menuedit() {
        processRunner.runMenuEditor();
    }

    function updateBgEffect() {
        startMenuOpacity = 100 - PlasmaCore.Theme.startMenuOpacity()
        backgroundColor = PlasmaCore.Theme.globalIconTheme() !== "breeze-dark" ? "white" : "#1A1A1A"
        Plasmoid.backgroundHints = PlasmaCore.Types.NoBackground
    }

    PlasmaCore.DataSource {
		id: executable
		engine: "executable"
		connectedSources: []
		onNewData: {
            blurEffectValid = data["stdout"].toString().includes("true");
            disconnectSource(sourceName)
        }

        function exec(cmd) {
            executable.connectSource(cmd)
        }
    }

    Component.onCompleted: {
        executable.exec('dbus-send --print-reply --dest=org.kde.KWin /Effects org.kde.kwin.Effects.areEffectsSupported array:string:"blur"')
        PlasmaCore.Theme.themeChanged.connect(updateBgEffect);
        if (plasmoid.hasOwnProperty("activationTogglesExpanded")) {
            plasmoid.activationTogglesExpanded = true
        }
    }

    Connections {
        target: plasmoid
        function onExpandedChanged() {
            /** PS: 这里为啥要将expanded又改成true，因为在切换全屏模式和普通模式的时候，
                会出现第一次设置为显示出来，但是会被其他地方重新设置为隐藏，
                所以这里要根据条件去判断一下当前是否需要showLauncher，来进行显示，
                注意只有当前是切换显示模式的时候，才会将showlauncher设置为true，其他任何地方都不会去修改showlauncher
            **/
            if (plasmoid.showLauncher && !plasmoid.expanded) {
                plasmoid.expanded = true
                plasmoid.showLauncher = false
            }
        }
        function onShowLauncherChanged() {
            plasmoid.expanded = true
        }
    }
} // root
